package com.heima.user.service.impl;

import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.common.exception.CustException;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.dtos.ActivateDTO;
import com.heima.model.user.dtos.LoginDTO;
import com.heima.model.user.pojos.ApUser;
import com.heima.user.mapper.ApUserMapper;
import com.heima.user.service.ApUserLoginService;
import com.heima.utils.common.AppJwtUtil;
import com.heima.utils.common.MD5Utils;
import com.heima.utils.common.SmsUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import sun.awt.windows.WWindowPeer;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.Date;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @作者 itcast
 * @创建日期 2021/9/28 9:17
 **/
@Service
@Slf4j
public class ApUserLoginServiceImpl implements ApUserLoginService {
    @Autowired
    ApUserMapper apUserMapper;

    @Autowired
    RedisTemplate<String, String> redisTemplate;


    /**
     * 用户请求验证码
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult sendCode(LoginDTO dto) {
        log.info("<===============用户发起请求,给他发送验证码===============>");
        //参数验证
        if (dto == null || dto.getPhone() == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }

        //判断用户是否存在
        ApUser apUser = apUserMapper.selectOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, dto.getPhone()));
        if (apUser == null) {
            CustException.cust(AppHttpCodeEnum.AP_USER_DATA_NOT_EXIST);
        }

        //生成验证码
        int code = (int) (Math.random() * 899999) + 100000;
        System.err.println(code);
        //发送验证码
        //测试用正式要改
        SendSmsResponse sendSmsResponse = null;
        try {
            sendSmsResponse = SmsUtils.sendSms(dto.getPhone(), String.valueOf(code));
        } catch (ClientException e) {
            e.printStackTrace();
        }

       if (!"OK".equals(sendSmsResponse.getCode())) {
           CustException.cust(AppHttpCodeEnum.SERVER_ERROR);
       }
        //验证码缓存到redis中
        HashOperations<String, Object, Object> opsForHash = redisTemplate.opsForHash();

        opsForHash.put("code:" + dto.getPhone(), "time", String.valueOf(System.currentTimeMillis()));
        opsForHash.put("code:" + dto.getPhone(), "code", String.valueOf(code));
        //  redisTemplate.expire("code" + dto.getPhone(),Long.valueOf(60), TimeUnit.SECONDS);
        log.info("<===============发送验证码成功===============>");
        return ResponseResult.okResult();
    }


    /**
     * app端登录 2.0版本
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult login(LoginDTO dto) {
        log.info("<======================用户请求登录开始=============================>");
        // 1. 校验参数,判断手机是否存在
        String phone = dto.getPhone();
        String password = dto.getPassword();
        if (StringUtils.isBlank(phone) || StringUtils.isBlank(password)) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        //1.1存在,判断手机格式是否正确
        if (!dto.getPhone().matches("^1[0-9]{10}$")) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "手机号格式有误!");
        }
        //  2.根据手机号 查询用户
        ApUser apUser = apUserMapper.selectOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, phone));
        if (apUser == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "用户不存在");
        }

        //3. 判断用户状态
        if (apUser.getStatus()) {
            CustException.cust(AppHttpCodeEnum.LOGIN_STATUS_ERROR, "用户状态异常");
        }

        //根据手机号查询redis
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();

        //查询验证码数据
        Map<Object, Object> codeMap = hash.entries("code:" + dto.getPhone());
        if (codeMap.size() == 0 || codeMap == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "请先获取验证码");
        }
        //查看验证码是否过期
        String codeTime = codeMap.get("time").toString();
        Long guoqiLong = Long.valueOf(codeTime);


        if (guoqiLong + 300000L < new Date().getTime()) {
            //验证码过期 删除 表
            hash.delete("code:" + dto.getPhone(), "time", "code");
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "验证码已过期");
        }

        //查询失败数据
        int frequency = 0;
        Map<Object, Object> failMap = hash.entries("fail:" + dto.getPhone());
        if (failMap != null && failMap.size() != 0) {
            //判断失败次数
            frequency = Integer.parseInt(failMap.get("frequency").toString());
        }

        //计算失败次数
        if (frequency == 3) {
            //获取时间戳
            Long failTime = Long.valueOf(failMap.get("time").toString()) + 60000l;
            long nowtime = new Date().getTime();

            if (failTime > nowtime) {
                Long daojishi = (failTime - nowtime) / 1000;
                CustException.cust(AppHttpCodeEnum.LOGIN_STATUS_ERROR, "错误次数过多 请" + daojishi + "秒后重试");
            }
        }
        //判断验证码是否正确
        String code = codeMap.get("code").toString();

        if (!code.equals(dto.getPassword())) {
            //不一致
            //更新失败次数表
            frequency = frequency + 1;
            if (frequency == 6) {
                //失败次数达到6次 冻结
                apUser.setStatus(true);
                apUserMapper.updateById(apUser);
                //删除失败次数表
                hash.delete("code:" + dto.getPhone(), "time", "code");
                hash.delete("fail:" + dto.getPhone(), "time", "frequency");
                CustException.cust(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR, "验证码输入错误多次,账号冻结,请联系管理员!");
            }

            hash.put("fail:" + dto.getPhone(), "frequency", String.valueOf(frequency));
            hash.put("fail:" + dto.getPhone(), "time", String.valueOf(System.currentTimeMillis()));
            return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR, "验证码错误");
        } else { //正确  返回信息  删除失败次数表  删除验证码表
            hash.delete("code:" + dto.getPhone(), "time", "code");
            hash.delete("fail:" + dto.getPhone(), "time", "frequency");
            // 颁发token
            String token = AppJwtUtil.getToken(Long.valueOf(apUser.getId()));

            Map result = new HashMap<>();
            result.put("token", token);
            apUser.setSalt("");
            apUser.setPassword("");
            result.put("user", apUser);
            log.info("<======================用户请求登录成功=============================>");
            return ResponseResult.okResult(result);
        }
    }

    /**
     * 邮件确认，更改用户状态
     *
     * @param phone
     * @return
     */
    @Override
    public ResponseResult updateUserStatus(String phone) {
        log.info("激活接口运行");
        if (StringUtils.isBlank(phone)) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "激活传入参数错误，可能被修改");
        }
        ApUser apUser = apUserMapper.selectOne(Wrappers.<ApUser>lambdaQuery()
                .eq(ApUser::getPhone, phone));
        if (apUser == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户不存在");
        }
        if (apUser.getStatus() == false) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_ALLOW, "正常状态无需激活");
        }
        /**
         * 0正常   false
         1锁定    true
         */
        apUser.setStatus(false);
        apUserMapper.updateById(apUser);
        return ResponseResult.okResult("用户状态更改成功");

    }

    @Autowired
    JavaMailSenderImpl javaMailSender;

    @Value("${spring.mail.username}")
    private String from;

    @Value("${spring.profiles.ip}")
    private String ip;

    @Value("${server.port}")
    private String port;

    /**
     * 激活发送邮件
     *
     * @param dto
     * @return
     */

    @Override
    public ResponseResult sendMineMail(ActivateDTO dto) {
        log.info("申请激活接口运行");
        String phone = dto.getPhone();
        String ToEmail = dto.getEmail();
        //1.判断邮箱是否合法
        if (!isEmail(ToEmail)) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "邮箱输入有误");
        }
        // 2. 校验参数  (  手机号 存在)
        if (StringUtils.isBlank(phone)) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "用户传入参数错误");
        }
        //查看用户是否存在
        ApUser apUser = apUserMapper.selectOne(Wrappers.<ApUser>lambdaQuery()
                .eq(ApUser::getPhone, phone));
        if (apUser == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "用户不存在");
        }
        //判断用户状态是否为锁定
        if (apUser.getStatus() == false) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_ALLOW, "正常状态无需激活");
        }
        try {

            MimeMessage message = javaMailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setSubject("黑马头条官方账号激活邮件");
            helper.setText(" <html ><head></head><body><h1>这是一封激活邮件,激活请点击以下链接</h1><h3><a href='http://localhost:5001/user/api/v1/login/Confirm/" + phone + "'>点击激活</a></h3></body></html>\n", true);
            helper.setTo(ToEmail);
            helper.setFrom(from);
            javaMailSender.send(message);
        } catch (MailException | MessagingException e) {
            e.printStackTrace();
            System.out.println("发送失败");
        }
        return ResponseResult.okResult("激活邮件发送成功");
    }

    /**
     * 正则邮箱验证
     *
     * @param string
     * @return
     */
    public static boolean isEmail(String string) {
        if (string == null) {
            return false;
        }
        String regEx1 = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
        Pattern p;
        Matcher m;
        p = Pattern.compile(regEx1);
        m = p.matcher(string);
        if (m.matches()) {
            return true;
        } else {
            return false;
        }
    }

}
